using System;
using System.Collections.Generic;

using Pegasus.Diagnostics;

namespace Pegasus.Workflow.Service
{
	/// <summary>
	/// The default persistence service and base class for custom persistence services 
	/// </summary>
	public abstract class WorkflowPersistenceService : IWorkflowService
	{
		// Local Instance Values
		private WorkflowService m_workflowService = null;

		/// <summary>
		/// Initializes a new instance of the <see cref="T:WorkflowPersistenceService"/> class.
		/// </summary>
		public WorkflowPersistenceService()
		{
		}

		/// <summary>
		/// Gets the workflow service that this service is attached to.
		/// </summary>
		/// <value>The workflow service.</value>
		public virtual WorkflowService WorkflowService
		{
			get
			{
				return m_workflowService;
			}
		}

		/// <summary>
		/// Starts this instance of the service.
		/// </summary>
		/// <param name="workflowService">The workflow service that owns this service.</param>
		public virtual void Start( WorkflowService workflowService )
		{
			// Check Parameters
			ParamCode.AssertNotNull( workflowService, "workflowService" );

			m_workflowService = workflowService;
		}

		/// <summary>
		/// Stops this instance of the service.
		/// </summary>
		public virtual void Stop()
		{
			m_workflowService = null;
		}

		/// <summary>
		/// Registers the new workflow context.
		/// </summary>
		/// <param name="context">The context.</param>
		/// <returns>The workflow Id for this new workflow</returns>
		public virtual int RegisterNewWorkflowContext( WorkflowContext context )
		{
			// Check Parameters
			ParamCode.AssertNotNull( context, "context" );

			int workflowId = OnRegisterNewWorkflowContext( context );

			// Set the new default status to idle
			context.Workflow.SetDefaultStatus( WorkflowStatus.Idle );

			return workflowId;
		}

		/// <summary>
		/// Saves the workflow context.
		/// </summary>
		/// <param name="context">The context.</param>
		/// <param name="unlock">if set to <c>true</c> [unlock].</param>
		public virtual void SaveWorkflowContext( WorkflowContext context, bool unlock )
		{
			// Check Parameters
			ParamCode.AssertNotNull( context, "context" );

			context.Workflow.FireBeforeSave();

			OnSaveWorkflowContext( context, unlock );
		}

		/// <summary>
		/// Loads the workflow context.
		/// </summary>
		/// <param name="workflowId">The workflow id.</param>
		/// <param name="readOnly">if set to <c>true</c> [read only].</param>
		/// <returns></returns>
		public virtual WorkflowContext LoadWorkflowContext( int workflowId, bool readOnly )
		{
			// Check Parameters
			ParamCode.AssertRange( workflowId, 1, int.MaxValue, "workflowId" );

			return OnLoadWorkflowContext( workflowId, readOnly );
		}

		/// <summary>
		/// Releases the workflow context.
		/// </summary>
		/// <param name="context">The context.</param>
		public virtual void ReleaseWorkflowContext( WorkflowContext context )
		{
			// Check Parameters
			ParamCode.AssertNotNull( context, "context" );
			OnReleaseWorkflowContext( context );
		}

		/// <summary>
		/// Registers a new workflow context with the persistence service.
		/// </summary>
		/// <param name="context">The context.</param>
		/// <returns></returns>
		protected abstract int OnRegisterNewWorkflowContext( WorkflowContext context );

		/// <summary>
		/// Saves the workflow context.
		/// </summary>
		/// <param name="context">The context.</param>
		/// <param name="unlock">if set to <c>true</c> [unlock].</param>
		protected abstract void OnSaveWorkflowContext( WorkflowContext context, bool unlock );

		/// <summary>
		/// Loads the workflow context.
		/// </summary>
		/// <param name="workflowId">The workflow id.</param>
		/// <param name="readOnly">if set to <c>true</c> [read only].</param>
		/// <returns></returns>
		protected abstract WorkflowContext OnLoadWorkflowContext( int workflowId, bool readOnly );

		/// <summary>
		/// Releases the workflow context.
		/// </summary>
		/// <param name="context">The context.</param>
		protected abstract void OnReleaseWorkflowContext( WorkflowContext context );

		/// <summary>
		/// Called by derived services to set the workflow id for new workflows
		/// </summary>
		/// <param name="context">The context.</param>
		/// <param name="workflowId">The workflow id.</param>
		protected void InitializeNewContext( WorkflowContext context, int workflowId )
		{
			// Check Parameters
			ParamCode.AssertNotNull( context, "context" );
			ParamCode.AssertRange( workflowId, 1, int.MaxValue, "workflowId" );

			context.InitializeNew( workflowId );
		}

		/// <summary>
		/// Setups the existing context.
		/// </summary>
		/// <param name="workflowId">The workflow id.</param>
		/// <param name="context">The context.</param>
		/// <param name="readOnly">if set to <c>true</c> [read only].</param>
		protected void InitializeExistingContext( int workflowId, WorkflowContext context, bool readOnly )
		{
			// Check Parameters
			ParamCode.AssertNotNull( context, "context" );

			context.InitializeExisting( m_workflowService, workflowId, readOnly );
		}

		/// <summary>
		/// Releases the context and marks it as read only
		/// </summary>
		/// <param name="context">The context.</param>
		protected void SetContextAsReadOnly( WorkflowContext context )
		{
			// Check Parameters
			ParamCode.AssertNotNull( context, "context" );

			context.SetAsReadOnly();
		}
	}
}
